﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json.Serialization;
using UcsHyperV.model.common;
using Newtonsoft.Json.Linq;
using System.Diagnostics;

namespace UcsHyperV.helper
{
    internal class PSHelper
    {
        public static void rename_vh()
        {
            //Get-VMNetworkAdapter -VMName test |Rename-VMNetworkAdapter -NewName "PublicAdapter"
            //Get-VMNetworkAdapter -VMName test |Rename-VMNetworkAdapter -NewName "PrivateAdapter"
            //Rename-VMNetworkAdapter

            using (Runspace runspace = RunspaceFactory.CreateRunspace())
            {
                runspace.Open();

                PowerShell ps = PowerShell.Create();
                ps.Runspace = runspace;
                ps.AddCommand("New-VM").AddParameters(
                    new Dictionary<string, string>()
                    {
                     {"Name", "test"},
                     {"MemoryStartupBytes", "2147483648"},
                     {"Generation", "1"},
                     {"NewVHDPath", @"C:\Hyper-V\Virtual Hard Disks\test.vhdx"},
                     {"NewVHDSizeBytes", "53687091200"},
                     {"BootDevice", "VHD"},
                     {"Path", @"C:\Hyper-V\Virtual Machines\test\"},
                     {"SwitchName", "public"},
                    }
                );

                foreach (PSObject result in ps.Invoke())
                {
                    Console.WriteLine(result);
                }
            }
        }


        internal static bool ShutdownInstance(int task_id, int instance_id, int progress)
        {
            return Execute("Stop-VM", new Dictionary<string, object>()
                   {
                     {"Name",instance_id},
                     { "Force",null},
                   }, task_id, progress, "Starting Instance");
        }


        public static bool StartInstance(int task_id, int instance_id, int progress)
        {
            return Execute("Start-VM", new Dictionary<string, object>()
                   {
                     {"Name",instance_id},
                   }, task_id, progress, "Starting Instance");
        }
        public static bool ReStartInstance(int task_id, int instance_id, int progress)
        {

            return Execute("ReStart-VM", new Dictionary<string, object>()
                   {
                     {"Name",instance_id},
                     { "Force",null},
                   }, task_id, progress, "ReStarting Instance");
        }
        public static bool CreateSystemDisk(int task_id, int instance_id,string temp_disk_path,string system_disk_path, int progress)
        {
            LogHelper.Info("temp_disk_path:"+temp_disk_path);
            LogHelper.Info("system_disk_path:"+ system_disk_path);
            return Execute("Copy-Item", new Dictionary<string, object>()
                   {
                     {"Path",temp_disk_path},
                     {"Destination",system_disk_path},
                   }, task_id, progress, "Create SystemDisk");
        }
        public static bool MountSystemDisk(int task_id, int instance_id, string system_disk_path, int progress)
        {
            return Execute("Add-VMHardDiskDrive", new Dictionary<string, object>()
                   {
                     {"Path",system_disk_path},
                     {"VMName",instance_id},
                     {"ControllerType","IDE"},
                     {"ControllerLocation",0},
                   }, task_id, progress, "Mount SystemDisk");
        }

        public static bool OnArp(int task_id, int instance_id, int progress, JsonObject data)
        {
            var private_mac = data.GetString("private_mac");
            var public_mac = data.GetString("public_mac");

            //ANY
            Execute("Add-VMNetworkAdapterAcl", new Dictionary<string, object>()
                   {
                     {"VMName",instance_id},
                     {"VMNetworkAdapterName","PublicAdapter"},
                     {"Direction","Both"},
                     {"LocalIPAddress","ANY"},
                     {"Action","Deny"},
                   }, task_id, progress, "Add Arp Any IP Deny Rule");


            Execute("Add-VMNetworkAdapterAcl", new Dictionary<string, object>()
                   {
                     {"VMName",instance_id},
                     {"VMNetworkAdapterName","PublicAdapter"},
                     {"Direction","Both"},
                     {"LocalMacAddress","ANY"},
                     {"Action","Deny"},
                   }, task_id, progress, "Add Arp ANY MAC Deny Rule");
            Execute("Add-VMNetworkAdapterAcl", new Dictionary<string, object>()
                   {
                     {"VMName",instance_id},
                     {"VMNetworkAdapterName","PublicAdapter"},
                     {"Direction","Both"},
                     {"LocalMacAddress",public_mac},
                     {"Action","Allow"},
                   }, task_id, progress, "Add Arp My MAC Rule");
            var public_ip = data.GetJsonArray("ip_address").GetJArray();
            foreach (var itoken in public_ip)
            {
                JsonObject item = new JsonObject(itoken.ToString());
                string ip = item.GetString("ip");
                LogHelper.Info(ip);
                Execute("Add-VMNetworkAdapterAcl", new Dictionary<string, object>()
                   {
                     {"VMName",instance_id},
                     {"VMNetworkAdapterName","PublicAdapter"},
                     {"Direction","Both"},
                     {"LocalIPAddress",ip},
                     {"Action","Allow"},
                   }, task_id, progress, "Add Arp Both My IP Rule :" + ip);
            }

            //这里要操作内网网卡的
            return true;
        }
        public static bool MountDataDisk(int task_id,string data_disk_path, int instance_id, int index, int progress)
        {
            return Execute("Add-VMHardDiskDrive", new Dictionary<string, object>()
                   {
                     {"Path",data_disk_path},
                     {"VMName",instance_id},
                     {"ControllerType","SCSI"},
                     {"ControllerLocation",index},
                   }, task_id, progress, "Mount SystemDisk");
        }
        public static bool CreateDataDisk(int task_id,string data_disk_path,int size, int progress)
        {
            return Execute("New-VHD", new Dictionary<string, object>()
                   {
                     {"Path",data_disk_path},
                     {"SizeBytes",size*1024*1024},
                   }, task_id, progress, "Create DataDisk");
        }
        /// <summary>
        /// 自动生成一个不重复的符合我司规则的mac地址
        /// </summary>
        /// <returns></returns>
        private static string MakeMacAddress(string head, int id)
        {
            try
            {
                string result = head + id.ToString("x8");
                if (result.Length == 12)
                {
                    result = result.Insert(2, ":");
                    result = result.Insert(5, ":");
                    result = result.Insert(8, ":");
                    result = result.Insert(11, ":");
                    result = result.Insert(14, ":");
                    return result;
                }
                else
                {
                    return null;
                }
            }
            catch (Exception)
            {

                return null;
            }
        }
        public static bool MountConfigISO(int task_id, int instance_id, int progress)
        {
            // Set-VMDvdDrive -VMName 24 -Path C:\Hyper-V\temp\iso\24.iso

            string iso_path = Config.temp_path + "\\iso\\" + instance_id + ".iso";
            return Execute("Set-VMDvdDrive", new Dictionary<string, object>()
                   {
                     {"Path",iso_path},
                     { "ControllerNumber","1"},
                     { "ControllerLocation","0"},
                     {"VMName",instance_id}
                   }, task_id, progress, "Mount ConfigISO");
        }
        public static bool CreateConfigISO(int task_id, int instance_id, int progress, JsonObject data)
        {
            //生成网卡MAC规则
            var private_mac = data.GetString("private_mac");
            var public_mac = data.GetString("public_mac");
            var dns = data.GetString("dns");
            string path = Config.temp_path + "\\" + instance_id + "\\";
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            if (!Directory.Exists(path + "\\iso"))
            {
                Directory.CreateDirectory(path);
            }
            var public_ip = data.GetJsonArray("ip_address");
            var private_ip = data.GetJsonArray("private_ip");
            var password = data.GetString("password");
            LogHelper.Info("111");
            File.WriteAllText(path + "action", "create");
            File.WriteAllText(path + "dns", dns);
            File.WriteAllText(path + "private_mac", private_mac);
            File.WriteAllText(path + "public_mac", public_mac);
            File.WriteAllText(path + "public_ip", public_ip.ToString());

            File.WriteAllText(path + "private_ip", private_ip.ToString());

            File.WriteAllText(path + "password", password);
            string iso_path = Config.temp_path + "\\iso\\" + instance_id + ".iso";
            string output = "";
            using (Process process = new Process())
            {
                process.StartInfo.FileName = "OSCDimg.exe";
                process.StartInfo.Arguments = "-h -lTEST_ISO -m -n -o " + path + " " + iso_path;
                process.StartInfo.CreateNoWindow = true;// 隐藏窗口运行
                process.StartInfo.RedirectStandardError = true;// 重定向错误流
                process.StartInfo.RedirectStandardInput = true;// 重定向输入流
                process.StartInfo.RedirectStandardOutput = true;// 重定向输出流
                process.StartInfo.UseShellExecute = false;
                process.Start();
                process.StandardInput.AutoFlush = true;
                output = process.StandardOutput.ReadToEnd();//读取结果
                process.WaitForExit();
                process.Close();
            }
            if (output.Contains("Error"))
            {
                NotifyHelper.Notify(task_id, 5, "Create Config ISO Error!");
                Console.WriteLine(output);
                return false;
            }
            NotifyHelper.Notify(task_id, 5, "Create Config ISO Success!");
            return true;
        }
        public static bool CreateInstance(int task_id, int instance_id, int cpu, int ratio, long memory, long bandwidth,JsonObject data)
        {
            var private_mac = data.GetString("private_mac");
            var public_mac = data.GetString("public_mac");
            Console.WriteLine(private_mac);
            Console.WriteLine(public_mac);
            if (Execute("New-VM", new Dictionary<string, object>()
                   {
                     {"Name",instance_id},
                     {"MemoryStartupBytes",memory*1024*1024},
                     {"Generation", "1"},
                     {"BootDevice", "VHD"},
                     {"Path",Config.instance_path},
                     {"SwitchName", Config.public_switch},
                   }, task_id, 10, "Create Instance")
                && Execute("Set-VMProcessor", new Dictionary<string, object>()
                   {
                     {"VMName",instance_id},
                     {"Count",cpu},
                     {"Reserve", "10"},
                     {"Maximum", ratio},
                   }, task_id, 20, "Set Processor")
                && Execute("Rename-VMNetworkAdapter", new Dictionary<string, object>()
                   {
                     {"VMName", instance_id},
                     {"Name", "网络适配器"},
                     {"NewName", "PublicAdapter"}
                   }, task_id, 30, "Rename PublicAdapter")

                && Execute("Add-VMNetworkAdapter", new Dictionary<string, object>()
                   {
                     {"VMName", instance_id},
                     {"SwitchName", Config.private_switch},
                     {"Name", "PrivateAdapter"}
                   }, task_id, 35, "Add NetworkAdapter")
                && Execute("Set-VMNetworkAdapter", new Dictionary<string, object>()
                   {
                     {"VMName", instance_id},
                     {"Name", "PublicAdapter"},
                     {"StaticMacAddress", public_mac},
                     {"MaximumBandwidth", bandwidth * 1000*1000}
                    //
                   }, task_id, 38, "Set PublicAdapter MacAddress")
                && Execute("Set-VMNetworkAdapter", new Dictionary<string, object>()
                   {
                     {"VMName", instance_id},
                     {"Name", "PrivateAdapter"},
                     {"StaticMacAddress", private_mac},
                     {"MaximumBandwidth", bandwidth * 1000*1000}
                    //
                   }, task_id, 40, "Set PrivateAdapter MacAddress"))
            {
                Console.WriteLine("Success!");
                return true;
            }
            return false;
        }
        public static bool Execute(string cmd, Dictionary<string, object> param, int task_id, int progress, string message)
        {
            var notify = new Notify();
            notify.task_id = task_id;
            notify.progress = progress;
            using (Runspace runspace = RunspaceFactory.CreateRunspace())
            {
                runspace.Open();
                PowerShell ps = PowerShell.Create();
                ps.Runspace = runspace;
                ps.AddCommand(cmd).AddParameters(param);
                var results = ps.Invoke();

                foreach (var error in ps.Streams.Error)
                {
                    if (error.Exception.InnerException != null)
                    {
                        notify.notify_message = message + " Error:" + error.Exception.InnerException.Message;
                        Console.WriteLine(error.Exception.InnerException.Message);
                    }
                    else
                    {
                        notify.notify_message = message + " Error:" + error.Exception.Message;
                        Console.WriteLine(error.Exception.Message);
                    }
                }
                if (ps.HadErrors)
                {
                    NotifyHelper.Notify(notify);
                    return false;
                }
                else
                {
                    foreach (PSObject result in results)
                    {
                        Console.WriteLine(result);
                    }
                }
                notify.notify_message = message + " Success!";
                NotifyHelper.Notify(notify);
                return true;
            }
        }
    }
}